package client.net.io;

import client.Client;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import shared.util.Pair;

/**
 * This class handles writing out packets to the server.
 * 
 * @author Vincent Tsuei
 * @version 2012-11-16
 */
public class ClientOutputHandler implements Runnable {
    
    private boolean running = true;
    private final OutputStream os;
    private final Client client;
    private final ByteBuffer writeBuffer = ByteBuffer.allocate(4096);
    
    public ClientOutputHandler(Client client, OutputStream os) {
        this.client = client;
        this.os = os;
    }

    @Override
    public void run() {
        WritableByteChannel c = Channels.newChannel(os);
        while (running) {
            try {
                byte[] b = null; 
                Boolean notify = null;
                try {
                    Pair<byte[], Boolean> pair = client.getNextOutputPacket();
                    b = pair.getLeft();
                    notify = pair.getRight();
                } catch (InterruptedException ex) {
                    Logger.getLogger(ClientOutputHandler.class.getName()).log(Level.INFO, "ClientOutputHandler interrupted.");
                    continue;
                    //Logger.getLogger(ClientOutputHandler.class.getName()).log(Level.SEVERE, null, ex); //Interrupt.
                }
                Logger.getLogger(ClientOutputHandler.class.getName()).log(Level.FINE, "Writing: {0}", Arrays.toString(b));
                writeBuffer.putInt(b.length); //Put packet size data
                writeBuffer.put(b); //Put actual packet
                writeBuffer.flip(); 
                c.write(writeBuffer); //Write out
                
                // Flush output stream and clear buffer
                os.flush();
                writeBuffer.clear();
                
                if (notify) {
                    synchronized(b) {
                        b.notify();
                    }
                }
            } catch (IOException ex) {
                Logger.getLogger(ClientOutputHandler.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    
    /**
     * Shutdown this output handler.
     */
    public void shutdown() {
        running = false;
    }
    
}